/*
 *  glue.cpp
 *  EPPI-0.0
 *
 *  Created by Juan Carlos Garcia Orden on 05/02/09.
 *
 */

#include "glue.h"

GGlue::GGlue(ifstream &in, string cname, MecSystem *pSys)
:	Joint(in,cname,pSys),
	pointName(),
	tolerance(1.0e-3)
{	
	dim = parentSystem->dim;	/** Must be set always.  dim belongs to the mother class Body */
	
	char keyword[20];
	string auxs;				/** Aux string */
//	vector< vector<string> > auxsv;	/** Points of first body in first row. Second in second */	
	int numPoints;
	int i;
	vector<string>	vBodyNames;
	vector<string>	vPSetNames;
	string sysName;
	MecSystem* sys;	
	
	pNames.resize(2);
	vector<string> auxsv1(2);
	string line;
	string keyw;
	//istringstream iss;

	while (in >> keyword && strcmp(keyword,"ENDJOINT") ) 
	{
		// keyword has the BODY label
		if (!strcmp(keyword,"TOLERANCE")) in >> tolerance;
		if (!strcmp(keyword,"BODY"))
		{
			// FIRST body
			in >> auxs;					/** Reads the name of the body */
			vBodyNames.push_back(auxs);
			/** Extract the system name where the body is */
			sysName = getStringHead(auxs);
			in >> auxs;
			sys = parentSystem->getPTSystem(sysName);
			if(!auxs.compare("POINTS"))	/** Reads keyword POINTS */
			{
				getline(in,line);
				//cout << "line is " << line << "\n";
				istringstream iss1(line);
				while (iss1 >> keyw )
				{
					pointName = keyw;
					if(checkForSlash(pointName)==false)	//If it does not have slash, add system name
					{
						addSystemName(pointName,sysName);
					}
					pNames[0].push_back(pointName);	
					pointName.clear();
				}
				
				/*
				in >> numPoints;			// Reads the number of constrained points
				for (i=0; i<numPoints; ++i)
				{
					in >> pointName;			// Reads the name of the point
					if(checkForSlash(pointName)==false)	//If it does not have slash, add system name
					{
						addSystemName(pointName,sysName);
					}
					pNames[0].push_back(pointName);	
					pointName.clear();
				}
				*/
		
				// SECOND body
				sysName.clear();
		
				in >> auxs;					/** Reads keyword BODY */
				in >> auxs;					/** Reads the name of the body */
				vBodyNames.push_back(auxs);
				/** Extract the system name where the body is */
				sysName = getStringHead(auxs);	
		
				in >> auxs;					/** Reads keyword POINTS */
				getline(in,line);
				//cout << "line is " << line << "\n";
				istringstream iss2(line);
				while (iss2 >> keyw )
				{
					pointName = keyw;
					if(checkForSlash(pointName)==false)	//If it does not have slash, add system name
					{
						addSystemName(pointName,sysName);
					}
					pNames[1].push_back(pointName);	
					pointName.clear();
				}				
				/*
				in >> numPoints;			// Reads the number of constrained points
				for (i=0; i<numPoints; ++i)
				{
					in >> pointName;			// Reads the name of the point
					if(checkForSlash(pointName)==false)	//If it does not have slash, add system name
					{
						addSystemName(pointName,sysName);
					}			
					pNames[1].push_back(pointName);	
					pointName.clear();
				}
				*/
			}
		}
		else if (!strcmp(keyword,"POINTSET"))
		{
			in >> auxs;	// First Pointset name (system/name)
			vPSetNames.push_back(auxs);
			/** Extract the system name where the first pointset is */
			sysName = getStringHead(auxs);
			sys = parentSystem->getPTSystem(sysName);			
			
			in >> auxs;	// POINTSET label
			in >> auxs;	// Second Pointset name (system/name)
			vPSetNames.push_back(auxs);
			searchSharedPointsPSets(vPSetNames);
			}
		if(!auxs.compare("BODY"))	// This means that just body names have been provided
		{
			// SECOND body
			in >> auxs;					/** Reads the name of the body */
			vBodyNames.push_back(auxs);
		
			// Points sharing coordinated must be identified in both bodies
			searchSharedPoints(vBodyNames);
		}
		/*
		cout << "La matriz pNames queda \n";
		for(i=0; i<pNames[0].size();++i)
		{
			cout << "\t" << pNames[0][i];
		}
		cout << "\n";
		for(i=0; i<pNames[1].size();++i)
		{
			cout << "\t" << pNames[1][i];
		}
		cout << "\n";
		*/
		// pNames has now the names of the points to glue, one by one

		for(i=0; i<pNames[0].size(); ++i)
		{
			auxsv1[0] = pNames[0][i];
			auxsv1[1] = pNames[1][i];
			sys->changePointName(auxsv1[0],auxsv1[1]);			
		}
		if(parentSystem->getProcNum()==parentSystem->getRankNum() ) cout << "	Joint " << name << " succesfully read \n";
	}
}

// ***
/*
void GGlue::setPTPointsComp()
{
	int j, k;
	vector<string> auxs;
	map<string, Point*, less<string> > maux;
	pair<string,Point*> mauxEntry;
	pair<string,int> sharedEntry;
	
	for(j=0; j<vComponents.size(); j++)		
	//Loop on the components
	{
		auxs = (vComponents[j]->getPointNames());
		for(k=0; k<auxs.size(); k++)		
		// Loop on the names of the points within each component
		{
			/ If the point it is not at the local process ... /
			if( (parentSystem->checkIfPointProcess(auxs[k]))==false )
			{
				/ ...  create it at root system, copying the original point from the remote process
				parentSystem->createPointAtRoot( parentSystem->getPTPoint(auxs[k]) );
				// ...  and add the name of the shared point at the remote process
//				cout << "Nombre del sistema = " << parentSystem->name << endl;
//				cout << "en el proceso = " << parentSystem->getProcNum() << endl;
//				cout << "Nombre del punto = " << auxs[k] << endl;
				parentSystem->addRemoteSharedPoint(auxs[k],parentSystem->getProcNum());
			}
			mauxEntry.first = auxs[k];
			mauxEntry.second = (parentSystem->getPTPointLocal(auxs[k]));
			maux.insert(mauxEntry);
		}
		vComponents[j]->setMPoints(maux);
		maux.clear();
	}
}

// ***

void GGlue::setPTPointsLoad()
{
	int j, k;
	vector<string> auxs;
	map<string, Point*, less<string> > maux;
	pair<string,Point*> mauxEntry;
	pair<string,int> sharedEntry;
	
	for(j=0; j<vLoads.size(); j++)		
	//Loop on the Loads
	{
		auxs = (vLoads[j]->getPointNames());
		for(k=0; k<auxs.size(); k++)		
		// Loop on the names of the points within each component
		{
			// If the point it is not at the local process ...
			if( (parentSystem->checkIfPointProcess(auxs[k]))==false )
			{
				// ...  create it at root system, copying the original point from the remote process
				parentSystem->createPointAtRoot( parentSystem->getPTPoint(auxs[k]) );
				// ...  and add the name of the shared point at the remote process
				parentSystem->addRemoteSharedPoint(auxs[k],parentSystem->getProcNum());
			}
			mauxEntry.first = auxs[k];
			mauxEntry.second = (parentSystem->getPTPointLocal(auxs[k]));
			maux.insert(mauxEntry);
		}
		vLoads[j]->setMPoints(maux);
		maux.clear();
	}

}
*/
// ***

void GGlue::setPTPointsCons()
{
}

// ***
/*
void GGlue::setPTPoints()
{
	int i;
	for(i=0;i<vPointNames.size();i++)
	{
		vPoints.push_back( parentSystem->getPTPointLocal(vPointNames[i]) );
	}
}
*/
// ***
/*
void GGlue::setPTBodies()
{}
*/
// ***

void GGlue::setPPointSurface()
{}

// ***
/*
void GGlue::writeFileGraph(ofstream &fGraph, string& gFormat)
{}
*/
// ***

void GGlue::writeMSH(ofstream &fGraph)
{}

// ***

void GGlue::writeVTU(ofstream &fGraph)
{
	localFGraph << "<?xml version=\"1.0\"?>\n";
	localFGraph << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
	localFGraph << "	<UnstructuredGrid>\n";
	localFGraph << "		<Piece NumberOfPoints=\"" << 0 << "\" NumberOfCells=\"" << 0 << "\">\n";
	localFGraph << "			<Points>\n";
	localFGraph << "				<DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "			</Points>\n";
	localFGraph<< "			<Cells>\n";
	localFGraph << "				<DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">";
	
	localFGraph << "\n";
	localFGraph << "					";
	
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "				<DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "					";
	
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "				<DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "					";
	
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph<< "			</Cells>\n";
	
	localFGraph << "		</Piece>\n";
	
	localFGraph << "	</UnstructuredGrid>\n";
	localFGraph << "</VTKFile>\n";	
}

// ***

void GGlue::writeOOGL(ofstream &fGraph)
{}

// ***

void GGlue::searchSharedPoints(vector<string>& vBodyNames)
{
	int i;
	int j;
	string pName;
	string pName1;	

	//cout << "Body0 es " << vBodyNames[0] << "\n";
	//cout << "Body1 es " << vBodyNames[1] << "\n";
	
	string sysName0 = getStringHead(vBodyNames[0]);
	MecSystem* sys0 = parentSystem->getPTSystem(sysName0);
	Body* body0 = sys0->mBodies[vBodyNames[0]];
	

	string sysName1 = getStringHead(vBodyNames[1]);
	MecSystem* sys1 = parentSystem->getPTSystem(sysName1);
	Body* body1 = sys1->mBodies[vBodyNames[1]];


	vector<double> coorB0(dim);
	vector<double> coorB1(dim);

//	map<string, vector<double>, less<string> >::iterator kk;
	
	// Brute force: compare each point of Body0 with all points of Body1
	// Loop on Body0
	for(i=0; i<body0->vPointNamesSurface.size(); ++i)
	{
		pName = body0->vPointNamesSurface[i];

		if(checkForSlash(pName)==false)	addSystemName(pName,sysName0);	//If it does not have slash, add system name
		
		// Check that the name is not "given", as it happens for the fixed point of flexchain1
		if (getStringTail(pName).compare("given"))
		{
			coorB0 = sys0->getCoordsPoint(pName);
			//		cout << "pointNames del sistema " << sys0->name << "\n";
			//		for(kk=sys0->pointNames.begin(); kk!=sys0->pointNames.end(); ++kk)	cout << kk->first << "\t" << kk->second[0] << "\t" << kk->second[1] << "\t" << kk->second[2] <<"\n";
//					cout << "** Mirando el punto " << pName << "\n";
//					cout << "** de coordenadas " << coorB0[0] << "," << coorB0[1] << "," << coorB0[2] << "\n";
		
			for(j=0; j<body1->vPointNamesSurface.size(); ++j)	// Loop on Body1
			{
				pName1 = body1->vPointNamesSurface[j];
				if(checkForSlash(pName1)==false)	addSystemName(pName1,sysName1);	//If it does not have slash, add system name
				
				// Check that the name is not "given", as it happens for the fixed point of flexchain1
				if (getStringTail(pName1).compare("given"))
				{
					coorB1 = sys1->getCoordsPoint(pName1);
					//cout << "Mirando el punto " << pName1 << "\n";
					//cout << "de coordenadas " << coorB1[0] << "," << coorB1[1] << "," << coorB1[2] << "\n";

//					if (equal(coorB0.begin(),coorB0.end(),coorB1.begin())==true)	// Strict match. Shared point found
					if (lTwoNorm(coorB0,coorB1)<=tolerance)	// Within tolerance. Shared point found
					{
						//cout << " point found ****** \n";
						pNames[0].push_back(pName);
						pNames[1].push_back(pName1);				
					}
				}
			}
		}
	}
}

// ***

void GGlue::searchSharedPointsPSets(vector<string>& vPSetNames)
{
	
	int i;
	int j;
	string pName;
	string pName1;	
	
	//cout << "pset0 es " << vPSetNames[0] << "\n";
	//cout << "pset1 es " << vPSetNames[1] << "\n";
	
	string sysName0 = getStringHead(vPSetNames[0]);
	MecSystem* sys0 = parentSystem->getPTSystem(sysName0);
	vector<string>	PSet0 = sys0->pointSets[vPSetNames[0]];
	
	string sysName1 = getStringHead(vPSetNames[1]);
	MecSystem* sys1 = parentSystem->getPTSystem(sysName1);
	vector<string>	PSet1 = sys1->pointSets[vPSetNames[1]];
	
	vector<double> coorB0(dim);
	vector<double> coorB1(dim);
	
	// Brute force: compare each point of PSet0 with all points of PSet1
	// Loop on PSet0
	for(i=0; i<PSet0.size(); ++i)
	{
		pName = PSet0[i];
		if(checkForSlash(pName)==false)	addSystemName(pName,sysName0);	//If it does not have slash, add system name
		// Check that the name is not "given", as it happens for the fixed point of flexchain1
		if (getStringTail(pName).compare("given"))
		{
			coorB0 = sys0->getCoordsPoint(pName);
			//cout << "** Mirando el punto " << pName << "\n";
			//cout << "** de coordenadas " << coorB0[0] << "," << coorB0[1] << "," << coorB0[2] << "\n";

			for(j=0; j<PSet1.size(); ++j)	// Loop on Body1
			{
				pName1 = PSet1[j];
				if(checkForSlash(pName1)==false)	addSystemName(pName1,sysName1);	//If it does not have slash, add system name
				// Check that the name is not "given", as it happens for the fixed point of flexchain1
				if (getStringTail(pName1).compare("given"))
				{
					coorB1 = sys1->getCoordsPoint(pName1);
					//cout << "Mirando el punto " << pName1 << "\n";
					//cout << "de coordenadas " << coorB1[0] << "," << coorB1[1] << "," << coorB1[2] << "\n";

					if (lTwoNorm(coorB0,coorB1)<=tolerance)	// Within tolerance. Shared point found
					{
						//cout << " point found ****** \n";
						pNames[0].push_back(pName);
						pNames[1].push_back(pName1);				
					}					
				}
			}
		}
	}
	/*
	//	map<string, vector<double>, less<string> >::iterator kk;
	
	// Brute force: compare each point of  with all points of Body1
	// Loop on Body0
	for(i=0; i<body0->vPointNamesSurface.size(); ++i)
	{
		pName = body0->vPointNamesSurface[i];
		
		if(checkForSlash(pName)==false)	addSystemName(pName,sysName0);	//If it does not have slash, add system name
		
		// Check that the name is not "given", as it happens for the fixed point of flexchain1
		if (getStringTail(pName).compare("given"))
		{
			coorB0 = sys0->getCoordsPoint(pName);
			//		cout << "pointNames del sistema " << sys0->name << "\n";
			//		for(kk=sys0->pointNames.begin(); kk!=sys0->pointNames.end(); ++kk)	cout << kk->first << "\t" << kk->second[0] << "\t" << kk->second[1] << "\t" << kk->second[2] <<"\n";
			//					cout << "** Mirando el punto " << pName << "\n";
			//					cout << "** de coordenadas " << coorB0[0] << "," << coorB0[1] << "," << coorB0[2] << "\n";
			
			for(j=0; j<body1->vPointNamesSurface.size(); ++j)	// Loop on Body1
			{
				pName1 = body1->vPointNamesSurface[j];
				if(checkForSlash(pName1)==false)	addSystemName(pName1,sysName1);	//If it does not have slash, add system name
				
				// Check that the name is not "given", as it happens for the fixed point of flexchain1
				if (getStringTail(pName1).compare("given"))
				{
					coorB1 = sys1->getCoordsPoint(pName1);
					//cout << "Mirando el punto " << pName1 << "\n";
					//cout << "de coordenadas " << coorB1[0] << "," << coorB1[1] << "," << coorB1[2] << "\n";
					
					//					if (equal(coorB0.begin(),coorB0.end(),coorB1.begin())==true)	// Strict match. Shared point found
					if (lTwoNorm(coorB0,coorB1)<=tolerance)	// Within tolerance. Shared point found
					{
						//cout << " point found ****** \n";
						pNames[0].push_back(pName);
						pNames[1].push_back(pName1);				
					}
				}
			}
		}
	}
	 */
}

// ***
/*
void GGlue::writeFileTemp(const double&, ofstream &)
{}
*/
// ***
/*
void GGlue::setIniPosJoint(vector<double>& iniValues)
{}
*/